iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0

多態

多態指的是一個引用型別 使用super class ,但是contructor(構造器)使用sub class

多態只著重在方法 的部分,屬性是沒有多態的。

也可以稱做sub class 物件的多態性。

範例:

class Person {
	String name;
	
	public void eat() {
		System.out.println("Person need eat.");
	}
}

class Man extends Person {
	
	// method override
	public void eat() {
		System.out.println("Man eat a lots of meat");
	}
}

public class PersonTest {
	public static void main(String[] args) {
	
		// sub class object多態性
		Person person = new Man();
		
		person.eat(); // Man eat a lots of meat
	}

}

super class : Person

sub class : Man

格式:

Person person = new Man();

虛擬方法調用

編譯時會認為person 的方法是看Person class ,但是當實際調用時會調用Man class 中的方法。

多態性使用的前提

  • 有繼承關係,即有super class & sub class
  • 要有方法重寫(override)

當使用多態性的方式去宣告一個物件時,不能使用一般的方式去使用在sub class 中所宣告特有屬性方法


向下轉型

使用強制類型轉換的方式,可以讓使用多態sub class 調用sub class 中特有的屬性方法

例如:

class Person {
	String name;
	
	public void eat() {
		System.out.println("Person need eat.");
	}
}

class Man extends Person {
	double height;
	// method override
	public void eat() {
		System.out.println("Man eat a lots of meat");
	}
	
	public void drink() {
	System.out.println("Man drink water");
	}
}

class Child extends Person {
}

public class PersonTest {
	public static void main(String[] args) {
	
		// sub class object多態性
		Person person = new Man();
	
		person.eat(); // Man eat a lots of meat
		
		// 會錯誤
		// person.height;
		// person.drink();
		
		Man man = (Man) person;
		
		//可以正常使用
		person.height;
		person.drink();
		
		Person person1 = new Child();
		Man child = (Man) person1;
		
		// 會錯誤 ClassCastException
		// child.height;
		// child.drink();
		
	}

}

這邊可以看到有2個地方註釋起來並寫上會錯誤

  1. person.height
    • 由於已經將類型 宣告為Person 了,所以是無法直接去使用在Man 中宣告的屬性方法
    • 必須透過強制類型轉換 的方式去將person 轉換並賦值,如上面的Man man = (Man) person;
    • 由於person 紀錄的是一個在Heap 中的位址值 ,所以當這樣宣告時,man 所存的值也是和person 紀錄相同的位址值 。(之前在陣列中有提到過,如果賦值的是 基本數據類型時,都只是記錄存放在Heap中的位址值 ,當Heap中的值更改時,因為變數的值都是指向同一個地方,不管使用哪一個變數去查值時,結果都是去找該位址值中的值)
  2. child.height
    • 在做強制類型轉換時,對於編譯器來說,PersonMansuper class ,所以它不會出現錯誤。
    • 但是ManChild 沒有任何關係,所以會出現ClassCastException (類型轉換異常)。

instanceOf

如果要在這樣的情況下去使用時,建議使用instanceOf 先進行判斷,確定沒問題了再去做強制類型轉換的動作。

例如:

class Person {
	String name;
	
	public void eat() {
		System.out.println("Person need eat.");
	}
}

class Man extends Person {
	double height;
	// method override
	public void eat() {
		System.out.println("Man eat a lots of meat");
	}
	
	public void drink() {
	System.out.println("Man drink water");
	}
}

class Child extends Person {
}

public class PersonTest {
	public static void main(String[] args) {
	
		// sub class object多態性
		Person person = new Man();
	
		person.eat(); // Man eat a lots of meat
		
		// 會錯誤
		// person.height;
		// person.drink();
		
		if(person instanceOf Man) {
			Man man = (Man) person;
			//可以正常使用
			person.height;
			person.drink();
		}
		
		Person person1 = new Child();
		
		// always false, because person1 not Child sub class
		if(person1 instanceOf Child) {
			Man child = (Man) person1;
		}
		
		if(person1 instanceOf Child) {
			Child child = (Child) person1;
			System.out.println("我成功轉換了") //我成功轉換了
		}
		
	}

}
💡 "a instaceOf b":指的是問 "a" 是否為 "b" 的 "sub class",會返回一個 "true" 或 "false"。
💡
"a instanceOf b" > "true"
"a instanceOf superb" > "true"
"b is superb's sub class"

多態的好處:

class Transportation {
	
	public void speed() {
		System.out.println("transpertation speed.");
	}
}

class Train extends Transportation {
	
	public void speed() {
		System.out.println("The train speed is 60 kilometers");
	}
}

class HighSpeedRail extends Transportation {
	public void speed() {
		System.out.println("The HighSpeedRail speed is 260 kilometers");
	}
}
public class TransportationTest {

	public static void main(String[] args) {
		TransportationTest test = new TransportationTest();
		Transportation train = new Train();
		Transportation highSpeedRail= new HighSpeedRail();
		test.currentSpeed(train); //The train speed is 60 kilometers
		test.currentSpeed(highSpeedRail); //The HighSpeedRail speed is 260 kilometers
	}
	
	public void currentSpeed(Transportation transportation) {
		transportation.speed();
	}
}

當使用多態性時,可以使擴充性更好,例如public void currentSpeed(Transportation transportation) ,由於使用多態性 的關係,Java會自動去找尋對應的sub class 中,是否有重寫的方法,若沒有則會去調用super class 中的方法,並且這樣的方式也可以減少很多重複的程式碼。

例如:沒有使用多態性的情況

public class TransportationTest {
	public static void main(String[] args) {
		TransportationTest test = new TransportationTest();
		Train train = new Train();
		HighSpeedRail highSpeedRail= new HighSpeedRail();
		test.currentSpeed(train); //The train speed is 60 kilometers
		test.currentSpeed(highSpeedRail); //The HighSpeedRail speed is 260 kilometers
	}
	
	public void currentSpeed(Train train) {
		train.speed();
	}
	
	public void currentSpeed(HighSpeedRail highSpeedRail) {
		highSpeedRail.speed();
	}
}

必須要依照不同的類別去寫不同的方法,由於範例中只有兩個sub class ,所以看起好像有點雞肋,但是當sub class 多了起來後,使用多態性的好處和優點就能夠漸漸浮現出來,並且當有新增的sub class時,也不必再特別為了這個sub class 增加新的方法。


上一篇
Day18-繼承 & override & super
下一篇
Day20-Object & 4方法
系列文
前端工程師的java學習紀錄38
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言